package cn.demoncat.util.lang;

import cn.demoncat.util.exception.BizRuntimeException;
import cn.demoncat.util.exception.ParamRuntimeException;
import cn.demoncat.util.lang.constant.CharConstant;
import cn.demoncat.util.lang.constant.CharsetConstant;
import cn.demoncat.util.lang.constant.StringConstant;
import cn.demoncat.util.lang.entity.ListStr;
import cn.demoncat.util.lang.entity.StringAppender;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.RegExUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 描述：字符串工具
 *
 * @author 延晓磊
 *
 * @since 2017年6月28日
 */
public final class StringUtil {

	/**
	 * 转换对象为字符串
	 *
	 * 1、String + String = StringBuilder.append(String)，如果String为null，会在append中拼接"null"
	 * 2、String + Object = StringBuilder.append(String.valueOf(Object))，如果Object为null，会在valueOf中返回“null”
	 * 3、结论：使用StringBuilder.append(null)、String.valueOf(null)、""+null，结果都是"null"
	 *
	 * @param o
	 * @return 如果为空，返回null
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年9月28日
	 */
	public static String toString(Object o) {
		if (o == null) {
			return null;
		} else {
			if (o instanceof String) {
				return (String) o;
			} else if (ArrayUtil.isArray(o)) {
				return ArrayUtil.objToString(o);
			}else {
				return o.toString();
			}
		}
	}

	/**
	 * 转换对象为字符串
	 * 
	 * @param o
	 * @return 如果为空，返回""
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年9月28日
	 */
	public static String toEmptyString(Object o) {
		if (o == null) {
			return StringConstant.EMPTY;
		} else {
			if (o instanceof String) {
				return (String) o;
			} else if (ArrayUtil.isArray(o)) {
				return ArrayUtil.objToString(o);
			}else {
				return o.toString();
			}
		}
	}

	/**
	 * 拼接字符串
	 *
	 * 注：使用StringBuilder.append()或 +号拼接，如果为null时会返回"null"，用本方法则返回''
	 *
	 * @param strs	字符串
	 * @return 如果字符串为null，将拼接''
	 *
	 * @author 延晓磊
	 * @since 2021年04月17日
	 */
	public static String concat(String ... strs){
		return new StringAppender().join(strs).toString();
	}

	/**
	 * 拼接字符串
	 *
	 * 注：使用StringBuilder.append()或 +号拼接，如果为null时会返回"null"，用本方法则返回''
	 *
	 * @param objs	对象
	 * @return 如果对象为null，将拼接''
	 *
	 * @author 延晓磊
	 * @since 2021年04月17日
	 */
	public static String concat(Object ... objs){
		return new StringAppender().join(objs).toString();
	}

	/**
	 * 空检验(校验不等于"null")
	 *
	 * @param str
	 * @return 如果为null/"null"返回true
	 *
	 * @author 延晓磊
	 *
	 * @since 2018年9月3日
	 */
	public static boolean isNull(String str) {
		return str == null || str.equals(StringConstant.NULL);
	}

	/**
	 * 空检验(校验不等于"null")
	 * 
	 * @param str
	 * @return 如果为null/'null'/''/' '返回true
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年9月3日
	 */
	public static boolean isBlank(String str) {
		return StringUtils.isBlank(str) || str.equals(StringConstant.NULL);
	}

	/**
	 * 空检验(校验不等于"null")
	 *
	 * @param o
	 * @return 如果为null/'null'/''/' '返回true
	 *
	 * @author 延晓磊
	 *
	 * @since 2018年9月3日
	 */
	public static boolean isBlank(Object o) {
		if (o == null) {
			return true;
		}
		// 非字符串 = false，空字符串 = true
		return o instanceof String && isBlank(o.toString());
	}

	/**
	 * 空校验
	 * 
	 * @param str
	 * @return 非空时返回str
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年8月31日
	 */
	public static String checkBlank(String str) {
		ParamEmptyUtil.checkBlank(str);
		return str;
	}

	/**
	 * 空检验(校验不等于"null")
	 *
	 * @param str
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2018年9月3日
	 */
	public static boolean isNotNull(String str) {
		return !isNull(str);
	}
	
	/**
	 * 空检验(校验不等于"null")
	 * 
	 * @param str
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年9月3日
	 */
	public static boolean isNotBlank(String str) {
		return !isBlank(str);
	}

	/**
	 * 空检验(校验不等于"null")
	 *
	 * @param o
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2018年9月3日
	 */
	public static boolean isNotBlank(Object o) {
		return !isBlank(o);
	}

	/**
	 * 空返null
	 *
	 * @param o
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2018年6月5日
	 */
	public static String toNull(String o) {
		return isBlank(o) ? null : o;
	}

	/**
	 * 空返null
	 *
	 * @param o
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2018年6月5日
	 */
	public static String trimToNull(String o) {
		return isBlank(o) ? null : o.trim();
	}

	/**
	 * 如果o为null，执行 consumer.accept(“”)
	 *
	 * 例：StringUtil.toEmpty(data.getIcon(), data::setIcon);
	 *
	 * @param o
	 * @param consumer
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2018年6月5日
	 */
	public static void toEmpty(String o, Consumer<String> consumer) {
		if (o == null) {
			consumer.accept(StringConstant.EMPTY);
		}
	}

	/**
	 * null转""
	 * 
	 * @param o
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年6月5日
	 */
	public static String toEmpty(String o) {
		return o == null || o.equals(StringConstant.NULL) ? StringConstant.EMPTY : o;
	}

	/**
	 * null转""，字符串trim
	 * 
	 * @param o
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年6月5日
	 */
	public static String trimToEmpty(String o) {
		return isBlank(o) ? StringConstant.EMPTY : o.trim();
	}

	/**
	 * 空转默认值
	 * 
	 * @param o		数据
	 * @param def	默认值
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年6月5日
	 */
	public static String toDefault(String o, String def) {
		return isBlank(o) ? def : o;
	}

	/**
	 * 空转默认值
	 *
	 * @param o		数据
	 * @param def	默认值
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2018年6月5日
	 */
	public static String toDefault(String o, Supplier<String> def) {
		return isBlank(o) ? def.get() : o;
	}

	/**
	 * 空转默认值，字符串trim
	 * 
	 * @param o		数据
	 * @param def	默认值
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年6月5日
	 */
	public static String trimToDefault(String o, String def) {
		return isBlank(o) ? def : o.trim();
	}

	/**
	 * 空转默认值，字符串trim
	 *
	 * @param o		数据
	 * @param def	默认值
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2018年6月5日
	 */
	public static String trimToDefault(String o, Supplier<String> def) {
		return isBlank(o) ? def.get() : o.trim();
	}

	/**
	 * 相等转默认值
	 * 
	 * @param o		数据
	 * @param target		比较目标
	 * @param def	默认值
	 * @return 如果o==t,返回def
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年6月5日
	 */
	public static String eqToDefault(String o, String target, String def) {
		if( (o == null && target == null) || (o != null && o.equals(target))) {
			return def;
		}
		return o;
	}
	
	/**
	 * 相等转null
	 * 
	 * @param o		数据
	 * @param target	比较目标
	 * @return 如果o==t,返回null
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年6月5日
	 */
	public static String eqToNull(String o, String target) {
		if(o != null && o.equals(target)) {
			return null;
		}
		return o;
	}

	/**
	 * 如果o非空，执行fn(o)
	 *
	 * @param o		对象
	 * @param fn	如果o非null执行fn.accept(o)
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年3月18日
	 */
	public static void consumer(String o, Consumer<String> fn){
		if (isNotBlank(o)) {
			fn.accept(o);
		}
	}
	
	/**
	 * 获取字符串，如果为空时抛异常
	 * 
	 * @param o
	 * @param msg	异常信息
	 * @return
	 * 
	 * @throws BizRuntimeException "msg"
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年6月5日
	 */
	public static String toException(String o, String msg) {
		if (isBlank(o)) {
			throw new BizRuntimeException(msg);
		}else {
			return o;
		}
	}
	
	/**
	 * 获取字符串，如果为空时抛异常
	 * 
	 * @param o
	 * @return
	 * 
	 * @throws ParamRuntimeException 参数为空
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年6月5日
	 */
	public static String toException(String o) {
		if (isBlank(o)) {
			throw ParamRuntimeException.NULL;
		}else {
			return o;
		}
	}

	/**
	 * 获取索引处的子串
	 * 
	 * @param str
	 * @param index  0首个，-1末个
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年12月23日
	 */
	public static String get(String str, int index) {
		// 非空
		if (str == null || str.isEmpty()) {
			return null;
		}
		// 倒数
		if (index < 0) {
			index = str.length() + index;
			if (index < 0) {
				return null;
			}
		}
		// 超限
		if (index > str.length() -1) {
			return null;
		}
		return String.valueOf(str.charAt(index));
	}
 
	/**
	 * 将Byte[]转换为UTF8的字符串
	 * 
	 * @param bytes
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年12月18日
	 */
	public static String getStr(byte[] bytes) {
		return getStr(bytes, null);
	}

	/**
	 * 将Byte[]转换为字符串
	 *
	 * @param bytes
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2017年12月18日
	 */
	public static String getStr(byte[] bytes, Charset charset) {
		if (bytes == null) {
			return null;
		}
		return new String(bytes, ObjectUtil.toDefault(charset, CharsetConstant.UTF8_CHARSET));
	}

	/**
	 * 使用UTF-8转换String为byte[]
	 * 
	 * @param str  	字符串
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年12月18日
	 */
	public static byte[] getBytes(String str) {
		return getBytes(str, null);
	}

	/**
	 * 转换String为byte[]
	 *
	 * @param str  	字符串
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2017年12月18日
	 */
	public static byte[] getBytes(String str, Charset charset) {
		if (str == null) {
			return null;
		}
		return str.getBytes(ObjectUtil.toDefault(charset, CharsetConstant.UTF8_CHARSET));
	}

	/**
	 * 转换二进制字符串为byte[]
	 * 
	 * @param code	二进制字符串（必须能被8整除，否则反转时会无法识别）
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年7月21日
	 */
	public static byte[] toBinaryBytes(String code) {
		if (code.length() % 8 != 0) {
			throw new IllegalArgumentException("参数长度必须被8整除，否则反转时无法识别");
		}
		byte[] data = new byte[code.length() / 8];
		int index = 0;
		for (int i = 0; i < code.length(); i += 8) {
			// 每8个编码，组合为1个byte
			data[index++] = (byte) Integer.parseInt(code.substring(i, i + 8), 2);
		}
		return data;
	}
	
	/**
	 * 将byte[]转换为二进制字符串
	 * 
	 * @param bytes
	 * 
	 * @return 二进制字符串（8位）
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年7月21日
	 */
	public static String toBinaryStr(byte[] bytes) {
		StringBuilder code = new StringBuilder();
		for (byte aByte : bytes) {
			// 将byte转换为二进制字符串
			code.append(toBinaryStr(aByte));
		}
		return code.toString();
	}
	
	/**
	 * 将byte转换为二进制字符串
	 * 
	 * @param b		数据（传参byte，转为int）
	 * 
	 * @return 二进制字符串（8位）
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年7月21日
	 */
	public static String toBinaryStr(int b) {
		// 补足8位：1 | 1 0000 0000 = 1 0000 0001
		b |= 256;
		// 转换二进制字符串
		String bs = Integer.toBinaryString(b);
		// 保留8位
		return bs.substring(bs.length() - 8);
	}

	/**
	 * 字符串转换Unicode
	 *
	 * @param string
	 * @return Unicode
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年2月19日
	 */
	public static String toUnicode(String string) {
		return UnicodeUtil.toUnicode(string);
	}

	/**
	 * Unicode 转字符串
	 *
	 * @param unicode   支持局部Unicode
	 * @return String
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年2月19日
	 */
	public static String parseUnicode(String unicode) {
		return UnicodeUtil.parseUnicode(unicode);
	}

	/**
	 * 功能描述：将iso-8859-1字符串转换为UTF-8，用于解决网络输入乱码
	 *
	 * @param str
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年5月21日
	 */
	public static String iso2Utf(String str) {
		if (isBlank(str)) {
			return StringConstant.EMPTY;
		}
		try {
			return new String(str.getBytes(CharsetConstant.ISO8859), StandardCharsets.UTF_8);
		} catch (UnsupportedEncodingException e) {
			return StringConstant.EMPTY;
		}
	}

	/**
	 * 
	 * 功能描述：将字符串转换为iso-8859-1，用于解决网络输出乱码
	 *
	 * @param str
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年5月21日
	 */
	public static String utf2iso(String str) {
		if (isBlank(str)) {
			return StringConstant.EMPTY;
		}
		try {
			return new String(str.getBytes(StandardCharsets.UTF_8), CharsetConstant.ISO8859);
		} catch (UnsupportedEncodingException e) {
			return null;
		}
	}

	/**
	 * 单词首字母转换为大写true/小写false
	 * 
	 * @param str
	 * @param upper
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2016年7月23日
	 */
	public static String firstUpperOrLower(String str, boolean upper) {
		if (upper) {
			return firstUpper(str);
		}else {
			return firstLower(str);
		}
	}
	
	/**
	 * 首字母大写
	 * 
	 * @param str
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年11月25日
	 */
	public static String firstUpper(String str) {
		return str.substring(0, 1).toUpperCase() + str.substring(1);
	}
	
	/**
	 * 首字母小写
	 * 
	 * @param str
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年11月25日
	 */
	public static String firstLower(String str) {
		return str.substring(0, 1).toLowerCase() + str.substring(1);
	}

	/**
	 * 转换字符串的编码格式转换成utf-8
	 * 
	 * @param str  
	 */
	public static String toUtf8(String str) {
		try {
			return java.net.URLEncoder.encode(str, CharsetConstant.UTF8);
		} catch (UnsupportedEncodingException e) {
			return null;
		}
	}

	/**
	 * 将字符串转换为UTF-8的输入流
	 *
	 * @param str
	 * @return 如果字符串为空，返回null
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年5月19日
	 */
	public static InputStream str2Ins(String str) {
		byte[] bytes = getBytes(str);
		if (bytes != null) {
			return new ByteArrayInputStream(bytes);
		}
		return null;
	}

	/**
	 * 功能描述：InputStream转换为String
	 *
	 * @param is
	 * @return
	 * @throws IOException
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年5月19日
	 */
	public static String ins2Str(InputStream is) throws IOException {
		if (is == null) {
			return null;
		}
		BufferedReader reader = new BufferedReader(new InputStreamReader(is));
		StringBuilder sb = new StringBuilder();
		String line;
		try {
			while ((line = reader.readLine()) != null) {
				sb.append(line).append(StringConstant.NEW_LINE);
			}
			return sb.toString();
		} finally {
			is.close();
		}
	}



	/**
	 * 去除Html标签
	 * 
	 * @param htmlStr
	 * @return
	 */
	public static String delHTMLTag(String htmlStr) {
		String regExScript = "<script[^>]*?>[\\s\\S]*?</script>"; // 定义script的正则表达式
		String regExStyle = "<style[^>]*?>[\\s\\S]*?</style>"; // 定义style的正则表达式
		String regExHtml = "<[^>]+>"; // 定义HTML标签的正则表达式

		Pattern pScript = Pattern.compile(regExScript, Pattern.CASE_INSENSITIVE);
		Matcher mScript = pScript.matcher(htmlStr);
		htmlStr = mScript.replaceAll(""); // 过滤script标签

		Pattern pStyle = Pattern.compile(regExStyle, Pattern.CASE_INSENSITIVE);
		Matcher mStyle = pStyle.matcher(htmlStr);
		htmlStr = mStyle.replaceAll(""); // 过滤style标签

		Pattern pHtml = Pattern.compile(regExHtml, Pattern.CASE_INSENSITIVE);
		Matcher mHtml = pHtml.matcher(htmlStr);
		htmlStr = mHtml.replaceAll(""); // 过滤html标签

		return htmlStr.trim(); // 返回文本字符串
	}

	/**
	 * 根据内容类型判断文件扩展名
	 * 
	 * @param contentType 内容类型
	 * @return
	 */
	public static String getFileExt(String contentType) {
		String fileExt = "";
		if ("image/jpeg".equals(contentType)) {
			fileExt = ".jpg";

		} else if ("audio/mpeg".equals(contentType)) {
			fileExt = ".mp3";

		} else if ("audio/amr".equals(contentType)) {
			fileExt = ".amr";

		} else if ("video/mp4".equals(contentType)) {
			fileExt = ".mp4";

		} else if ("video/mpeg4".equals(contentType)) {
			fileExt = ".mp4";
		}
		return fileExt;
	}

	/**
	 * Log4j的format
	 * 
	 * @param format	表达式：你好{}，验证码是{}
	 * @param args		动态数据，对应{}占位符数
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年9月15日
	 */
	public static String logFormat(String format, Object... args) {
		// 没有占位符
		if (args == null || args.length == 0 || StringUtils.isBlank(format) || !format.contains(StringConstant.LEFT_BRACE)) {
			return format;
		}
		// 解析 - 原生
		int formatLength = format.length();
		StringBuilder sd = new StringBuilder(formatLength + 50);
		// 已经处理到的位置
		int handledPosition = 0;
		// 占位符所在位置
		int delimitIndex;
		for (int i = 0; i < args.length; i++) {
			delimitIndex = format.indexOf(StringConstant.EMPTY_MAP, handledPosition);
			if (delimitIndex == -1) {
				// 剩余部分无占位符
				sd.append(format, handledPosition, formatLength);
				return sd.toString();
			}
			// 转义符
			if (delimitIndex > 0 && format.charAt(delimitIndex - 1) == CharConstant.BACKSLASH) {
				if (delimitIndex > 1 && format.charAt(delimitIndex - 2) == CharConstant.BACKSLASH) {
					// 转义符之前还有一个转义符，占位符依旧有效
					sd.append(format, handledPosition, delimitIndex - 1);
					sd.append(toEmptyString(args[i]));
					handledPosition = delimitIndex + 2;
				} else {
					// 占位符被转义
					i--;
					sd.append(format, handledPosition, delimitIndex - 1);
					sd.append(CharConstant.LEFT_BRACE);
					handledPosition = delimitIndex + 1;
				}
			} else {
				// 正常占位符
				sd.append(format, handledPosition, delimitIndex);
				sd.append(toEmptyString(args[i]));
				handledPosition = delimitIndex + 2;
			}
		}
		// 加入最后一个占位符后所有的字符
		sd.append(format, handledPosition, formatLength);
		return sd.toString();
	}

	/**
	 * 根据换行符切割字符串
	 * 
	 * @param text
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年4月26日
	 */
	public static String[] splitLine(String text) {
		return StringUtils.split(text,RegexpUtil.LINE);
	}

	/**
	 * 根据换行符切割字符串
	 * 
	 * @param text
	 * @param max 	切割数：-1表示不限制。如果实际切割数大于max，会将max之后的字符串拼接起来到[max-1]
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年4月26日
	 */
	public static String[] splitLine(String text, int max) {
		return StringUtils.split(text,RegexpUtil.LINE, max);
	}
	
	/**
	 * 根据空白切割字符串
	 * 
	 * @param text
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年4月26日
	 */
	public static String[] splitSpace(String text) {
		return StringUtils.split(text);
	}

	/**
	 * 根据空白切割字符串
	 * 
	 * @param text
	 * @param max 	切割数：-1表示不限制。如果实际切割数大于max，会将max之后的字符串拼接起来到[max-1]
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年4月26日
	 */
	public static String[] splitSpace(String text, int max) {
		return StringUtils.split(text, null, max);
	}
	
	/**
	 * 严格的逗号切割：不保留空串，为null时返回null，为""时返回[]
	 * 
	 * @param text
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年11月30日
	 */
	public static String[] splitStrict(String text) {
		return StringUtils.split(text,StringConstant.COMMA);
	}
	
	/**
	 * 逗号切割：保留空串，为null时返回null，为""时返回[]
	 * 
	 * @param text
	 * @return null > null, '' > [], '1,2' > [1,2]
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年11月30日
	 */
	public static String[] split(String text) {
		if (text == null) {
			return null;
		}
		if (text.isEmpty()) {
			return new String[0];
		}
		return text.split(StringConstant.COMMA, -1);
	}

	/**
	 * 逗号切割
	 * 
	 * @param text
	 * @return null > null, '' > [], '1,2' > [1,2]
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年11月30日
	 */
	public static List<String> splitToList(String text) {
		return CollectionUtil.toStrList(text);
	}

	/**
	 * 逗号切割
	 * 
	 * @param text
	 * @return null > null, '' > [], '1,2' > [1,2]
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年11月30日
	 */
	public static Set<String> splitToSet(String text) {
		return CollectionUtil.toStrSet(text);
	}

	/**
	 * 逗号切割
	 * 
	 * @param text
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年11月30日
	 */
	public static Long[] splitLong(String text) {
		String[] split = StringUtil.split(text);
		if (split != null) {
			Long[] longs = new Long[split.length];
			for (int i = 0; i < split.length; i++) {
				longs[i] = LongUtil.valueOf(split[i]);
			}
			return longs;
		}
		return null;
	}

	/**
	 * 逗号切割
	 * 
	 * @param text
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年11月30日
	 */
	public static Integer[] splitInt(String text) {
		String[] split = StringUtil.split(text);
		if (split != null) {
			Integer[] longs = new Integer[split.length];
			for (int i = 0; i < split.length; i++) {
				longs[i] = IntegerUtil.valueOf(split[i]);
			}
			return longs;
		}
		return null;
	}

	/**
	 * 逗号切割
	 * 
	 * @param text
	 * @return "" = [],"10,20" = [10,20]
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年11月30日
	 */
	public static List<Long> splitToLongList(String text) {
		return CollectionUtil.toLongList(text);
	}

	/**
	 * 逗号切割
	 * 
	 * @param text
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年11月30日
	 */
	public static List<Integer> splitToIntList(String text) {
		return CollectionUtil.toIntList(text);
	}

	/**
	 * 是否包含
	 *
	 * @param text
	 * @param str
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2018年11月30日
	 */
	public static boolean contains(String text, String str){
		return StringUtils.contains(text, str);
	}

	/**
	 * 是否包含,号
	 *
	 * @param text
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2018年11月30日
	 */
	public static boolean containsComma(String text){
		return StringUtils.contains(text, StringConstant.COMMA);
	}

	/**
	 * 是否包含空白
	 *
	 * @param text
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2018年11月30日
	 */
	public static boolean containsSpace(String text){
		return StringUtils.containsWhitespace(text);
	}

	/**
	 * 使用,号拼接多个字符串
	 * 
	 * @param text	N个字符串
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年1月9日
	 */
	public static String join(String... text) {
		if (ArrayUtils.isEmpty(text)) {
			return StringConstant.EMPTY;
		}
		return StringUtils.join(text, StringConstant.COMMA);
	}

	/**
	 * 使用,号拼接字符串列表
	 * 
	 * @param texts	N个字符串
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年1月9日
	 */
	public static String join(Collection<?> texts) {
		if (CollectionUtils.isEmpty(texts)) {
			return StringConstant.EMPTY;
		}
		return StringUtils.join(texts, StringConstant.COMMA);
	}

	/**
	 * 使用空格拼接多个字符串
	 *
	 * @param text	N个字符串
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年1月9日
	 */
	public static String joinSpace(String... text) {
		if (ArrayUtils.isEmpty(text)) {
			return StringConstant.EMPTY;
		}
		return StringUtils.join(text, StringConstant.SPACING);
	}

	/**
	 * 使用空格拼接字符串列表
	 *
	 * @param texts	N个字符串
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年1月9日
	 */
	public static String joinSpace(Collection<?> texts) {
		if (CollectionUtils.isEmpty(texts)) {
			return StringConstant.EMPTY;
		}
		return StringUtils.join(texts, StringConstant.SPACING);
	}

	/**
	 * 合并字符串
	 *
	 * @param a 字符串，以,分隔
	 * @param b 字符串，以,分隔
	 * @param unique 是否去重
	 * @return 字符串，以,分隔
	 *
	 * @author 延晓磊
	 * @since 2023年09月18日
	 */
	public static String merge(String a, String b, boolean unique){
		if (StringUtils.isBlank(a)) {
			return b;
		}else if (StringUtils.isBlank(b)) {
			return a;
		}else{
			a += StringConstant.COMMA + b;
			if (unique) {
				return join(splitToSet(a));
			}else{
				return a;
			}
		}
	}

	/**
	 * 截取字符串
	 * 
	 * @param str		字符串
	 * @param length	最多前length个
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年5月21日
	 */
	public static String trunc(String str, int length) {
		if (str == null) {
			return StringConstant.EMPTY;
		}
		if (str.length() <= length) {
			return str;
		}
		return str.substring(0, length);
	}

	/**
	 * 换行替换为逗号
	 *
	 * @param text
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2018年12月3日
	 */
	public static String replaceLine(String text) {
		return RegExUtils.replaceAll(text, RegexpUtil.LINE, StringConstant.COMMA);
	}

	/**
	 * 正则替换
	 *
	 * @param text		字符串
	 * @param regex		被替换的正则
	 * @param target	替换的目标
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年6月19日
	 */
	public static String replace(String text, String regex, String target) {
		return RegExUtils.replaceAll(text, regex, target);
	}

	/**
	 * 字符替换
	 *
	 * @param text		字符串
	 * @param search	被替换的字符串
	 * @param target	替换的字符串
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年6月19日
	 */
	public static String replaces(String text, String search, String target) {
		return StringUtils.replace(text, search, target);
	}

	/**
	 * 字符替换
	 *
	 * @param text		字符串
	 * @param searches	被替换的字符串
	 * @param targets	替换的字符串，与searchs对应
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年6月19日
	 */
	public static String replaces(String text, String[] searches, String[]  targets) {
		return StringUtils.replaceEach(text, searches, targets);
	}

	/**
	 * 正则删除
	 *
	 * @param text		字符串
	 * @param regex		被去除的正则
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年6月19日
	 */
	public static String remove(String text, String regex) {
		return RegExUtils.removeAll(text, regex);
	}

	/**
	 * 删除空格
	 *
	 * @param text		字符串
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年6月19日
	 */
	public static String remove(String text) {
		return StringUtils.deleteWhitespace(text);
	}

	/**
	 * 删除字符
	 *
	 * @param text		字符串
	 * @param searches	被删除的字符串
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年6月19日
	 */
	public static String removes(String text, String... searches) {
		if (ArrayUtils.isEmpty(searches)) {
			return text;
		}else if (searches.length == 1) {
			return StringUtils.remove(text, searches[0]);
		}else{
			return StringUtils.replaceEach(text, searches, ArrayUtil.fill(new String[searches.length], StringConstant.EMPTY));
		}
	}

	/**
	 * 删除前缀
	 *
	 * @param str
	 * @param start
	 * @return 112-1 = 12
	 */
	public static String removeStart(String str, String start){
		return StringUtils.removeStart(str, start);
	}

	/**
	 * 删除前缀
	 *
	 * @param str
	 * @param start
	 * @return 112-1 = 2
	 */
	public static String removeStarts(String str, String start){
		return StringUtils.stripStart(str, start);
	}

	/**
	 * 添加前缀（前缀非start时添加）
	 * 
	 * @param str	字符串
	 * @param start	前缀字符
	 * @return	11-1 = 11, 11-0 = 011
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年6月5日
	 */
	public static String addStart(String str, String start) {
		if (str.startsWith(start)) {
			return str;
		}
		return start + str;
	}

	/**
	 * 添加后缀（后缀非start时添加）
	 *
	 * @param str	字符串
	 * @param end	后缀字符
	 * @return	11-1 = 11, 11-0 = 110
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年6月5日
	 */
	public static String addEnd(String str, String end) {
		if (str.endsWith(end)) {
			return str;
		}
		return str + end;
	}

	/**
	 * 填充前缀（长度不足size时添加）
	 *
	 * @param str
	 * @param start
	 * @param size
	 * @return
	 */
	public static String padStart(String str, String start, int size){
		return StringUtils.leftPad(str, size, start);
	}

	/**
	 * 填充后缀（长度不足size时添加）
	 *
	 * @param str
	 * @param end
	 * @param size
	 * @return
	 */
	public static String padEnd(String str, String end, int size){
		return StringUtils.rightPad(str, size, end);
	}

	/**
	 * 树型切割
	 *
	 * @param text		字段串
	 * @param length	片段长度
	 *
	 * @return  101010,2 = [10,1010,101010]
	 */
	public static ListStr splitTree(String text, int length){
		ListStr list = ListStr.getInstance();
		for (int i = text.length()/length; i > 0 ; i--) {
			list.add(text.substring(0, text.length() - length * (i-1)));
		}
		return list;
	}

	/**
	 * xx_xx 转 xxXx
	 *
	 * @param x_x
	 * @return xX
	 * 
	 * @author yxl
	 *
	 * @since 2016年7月9日
	 */
	public static String parseLineToHump(String x_x) {
		// 全部小写
		x_x = x_x.toLowerCase();
		// 切割
		String[] names = x_x.split(StringConstant.UNDER_LINE);
		// _转换为驼峰
		StringBuilder name = new StringBuilder(names[0]);
		String temp;
		for (int i = 1; i < names.length; i++) {
			temp = names[i];
			name.append(temp.substring(0, 1).toUpperCase()).append(temp.substring(1));
		}
		return name.toString();
	}
	
	/**
	 * xxXX 转 xx_xx
	 *
	 * @param 	xX
	 * @return	x_x
	 * 
	 * @author yxl
	 *
	 * @since 2016年7月9日
	 */
	public static String parseHumpToLine(String xX) {
		// 拆分
		char[] charArray = xX.toCharArray();
		// 组装
		List<String> list = new ArrayList<>();
		String tmp =  String.valueOf(charArray[0]);
		list.add(tmp.toLowerCase());
		for (int i = 1; i < charArray.length; i++) {
			tmp = String.valueOf(charArray[i]);
			if (tmp.matches("[A-Z]")){
				//遇大写字母，前面加_并转换为小写
				list.add(StringConstant.UNDER_LINE);
				list.add(tmp.toLowerCase());
			} else{
				list.add(tmp);
			}
		}
		return StringUtils.join(list);
	}
 
	/**
	 * xx-xx 转 xxXx
	 *
	 * @param x_x	x-x
	 * @return xX
	 * 
	 * @author yxl
	 *
	 * @since 2016年7月9日
	 */
	public static String parseBarToHump(String x_x) {
		// 全部小写
		x_x = x_x.toLowerCase();
		// 切割
		String[] names = x_x.split(StringConstant.BAR);
		// -转换为驼峰
		StringBuilder name = new StringBuilder(names[0]);
		String temp;
		for (int i = 1; i < names.length; i++) {
			temp = names[i];
			name.append(temp.substring(0, 1).toUpperCase()).append(temp.substring(1));
		}
		return name.toString();
	}
	
	/**
	 * xxXX 转 xx-xx
	 *
	 * @param 	xX
	 * @return	x-x
	 * 
	 * @author yxl
	 *
	 * @since 2016年7月9日
	 */
	public static String parseHumpToBar(String xX) {
		// 拆分
		char[] charArray = xX.toCharArray();
		// 组装
		List<String> list = new ArrayList<>();
		String tmp = String.valueOf(charArray[0]);
		list.add(tmp.toLowerCase());
		for (int i = 1; i < charArray.length; i++) {
			tmp = String.valueOf(charArray[i]);
			if (tmp.matches("[A-Z]")){
				//遇大写字母，前面加_并转换为小写
				list.add(StringConstant.BAR);
				list.add(tmp.toLowerCase());
			} else{
				list.add(tmp);
			}
		}
		return StringUtils.join(list,null);
	}
	
	/**
	 * 子串搜索（暴力匹配/KMP算法）
	 * 
	 * @param str	字符串
	 * @param sub	子串
	 * 
	 * @return 首次出现的索引
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年7月27日
	 */
	public static int search(String str, String sub) {
		if (StringUtils.isAnyBlank(str, sub)) {
			return -1;
		}
		if (sub.length() == 1) {
			// 暴力匹配
			return searchByBruteForce(str, sub);
		}else {
			// KMP匹配
			return searchByKmp(str, sub, getKmpNext(sub));
		}
	}
	
	/**
	 * 子串搜索（暴力匹配）
	 * 
	 * @param str	字符串
	 * @param sub	子串
	 * 
	 * @return 首次出现的索引
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年7月27日
	 */
	public static int searchByBruteForce(String str, String sub) {
		// 转换为char[]
		char[] s1 = str.toCharArray();
		char[] s2 = sub.toCharArray();
		// 搜索
		int i = 0;
		int j = 0;
		while (i < s1.length && j < s2.length) {
			if (s1[i] == s2[j]) {
				// 匹配成功：继续匹配下一个字符
				i++;
				j++;
			}else {
				// 匹配失败：从子串的第一个字符开始重新匹配
				i = i - j + 1;
				j = 0;
			}
		}
		// 搜索完成
		return j == s2.length ? i - j : -1;
	}

	/**
	 * 子串搜索（KMP算法）
	 * 
	 * @param str	字符串
	 * @param sub	子串
	 * @param next	KMP算法的部分匹配值表
	 * 
	 * @return 首次出现的索引
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年7月27日
	 */
	public static int searchByKmp(String str, String sub, int[] next) {
		for (int i = 0, j = 0; i < str.length(); i++) {
			// 找到匹配的字符
			while(j > 0 && str.charAt(i) != sub.charAt(j)) {
				j = next[j-1];
			}
			// 匹配时，递增匹配数
			if (str.charAt(i) == sub.charAt(j)) {
				j++;
			}
			// 匹配成功
			if (j == sub.length()) {
				return i - j + 1;
			}
		}
		return -1;
	}
	
	/**
	 * 获取KMP算法的部分匹配值
	 * 
	 * @param target	搜索词
	 * 
	 * @return [部分匹配值]
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年7月27日
	 */
	public static int[] getKmpNext(String target) {
		// 部分匹配值表
		int[] next = new int[target.length()];
		// 1个字符的匹配值必然为0
		next[0] = 0;
		// 计算匹配值
		for (int i = 1, j = 0; i < target.length(); i++) {
			// 找到匹配的字符
			while(j > 0 && target.charAt(i) != target.charAt(j)) {
				j = next[j-1];
			}
			// 匹配时，增加匹配值
			if (target.charAt(i) == target.charAt(j)) {
				j++;
			}
			next[i] = j;
		}
		return next;
	}

	/**
	 * 字符统计
	 *
	 * @param str
	 * @return
	 *
	 * @author 延晓磊
	 * @since 2020年12月01日
	 */
	public static Map<String,Integer> charCount(String str){
		Map<String,Integer> map = new HashMap<>();
		if (StringUtils.isNotBlank(str)) {
			String s;
			for (char c : str.toCharArray()) {
				s = String.valueOf(c);
				if (map.containsKey(s)) {
					map.put(s, map.get(s) + 1);
				}else{
					map.put(s, 1);
				}
			}
		}
		return map;
	}

	/**
	 * 字符串统计的比对
	 *
	 * @param a  统计1
	 * @param b	 统计2
	 * @return [a的总数，b的重合数]
	 *
	 * @author 延晓磊
	 * @since 2020年12月01日
	 */
	public static int[] countComparison(Map<String,Integer> a, Map<String,Integer> b){
		// 为空
		if (MapUtil.isEmpty(a) || MapUtil.isEmpty(b)) {
			return new int[]{0,0};
		}
		// 非空
		int count = 0;
		int repeat = 0;
		Integer currCount;
		for (Map.Entry<String, Integer> entry : a.entrySet()) {
			// 总数
			count += entry.getValue();
			currCount = b.get(entry.getKey());
			if (currCount != null) {
				// 重合度
				repeat += Math.min(entry.getValue(), currCount);
			}
		}
		return new int[]{count, repeat};
	}

	/**
	 * 是否为 "字母、数字"
	 *
	 * @param str
	 * @return
	 *
	 * @author 延晓磊
	 * @since 2021年01月13日
	 */
	public static boolean isAlphanumeric(String str){
		return str.matches(RegexpUtil.AlphabetRex.ALPHABET_NUM);
	}

	/**
	 * 是否为 "字母"
	 *
	 * @param str
	 * @return
	 *
	 * @author 延晓磊
	 * @since 2021年01月13日
	 */
	public static boolean isAlpha(String str){
		return str.matches(RegexpUtil.AlphabetRex.ALPHABET);
	}

	/**
	 * 计算相似度
	 *
	 * @param strA
	 * @param strB
	 * @param scale 相似度小数位
	 * @return 0-1
	 *
	 * @author 延晓磊
	 * @since 2021年07月15日
	 */
	public static double getSimilar(String strA, String strB, int scale) {
		// 清除无效字符
		String newStrA, newStrB;
		if (strA.length() < strB.length()) {
			newStrA = removeInvalidChar(strB);
			newStrB = removeInvalidChar(strA);
		} else {
			newStrA = removeInvalidChar(strA);
			newStrB = removeInvalidChar(strB);
		}
		int temp = Math.max(newStrA.length(), newStrB.length());
		if(0 == temp) {
			// 两个都是空串，相似度为1
			return 1;
		}
		// 公共子串/最长的字符串 = 相似度
		return DoubleUtil.divide(scale, getSubString(newStrA, newStrB).length(), temp);
	}


	/**
	 * 清除无效字符（只保留汉字、数字、字母）
	 *
	 * @param str
	 * @return
	 *
	 * @author 延晓磊
	 * @since 2021年07月15日
	 */
	public static String removeInvalidChar(String str){
		StringBuilder sd = new StringBuilder(str.length());
		char c;
		for (int i = 0; i < str.length(); i++) {
			c = str.charAt(i);
			if(isValidChar(c)) {
				sd.append(c);
			}
		}
		return sd.toString();
	}
 
	/**
	 * 判断是否为有效字符（汉字、数字、字母）
	 *
	 * @param c
	 * @return
	 * 
	 * @author 延晓磊
	 * @since 2021年07月15日
	 */
	public static boolean isValidChar(char c) {
		return (c >= 0x4E00 && c <= 0X9FFF) || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9');
	}

	/**
	 * 求公共子串(不要求子串在所给的字符串中是连续的)，采用动态规划算法
	 *
	 * @param strA 字符串1
	 * @param strB 字符串2
	 * @return 公共子串
	 *
	 * @author 延晓磊
	 * @since 2021年07月15日
	 */
	public static String getSubString(String strA, String strB) {
		char[] chars_strA = strA.toCharArray();
		char[] chars_strB = strB.toCharArray();
		int m = chars_strA.length;
		int n = chars_strB.length;
		// 初始化矩阵数据, matrix[0][0]的值为0。
		// 如果字符数组chars_strA和chars_strB的对应位相同，则matrix[i][j]的值为左上角的值加1，
		// 否则，matrix[i][j]的值等于左上方最近两个位置的较大值，矩阵中其余各点的值为0
		int[][] matrix = new int[m + 1][n + 1];
		for (int i = 1; i <= m; i++) {
			for (int j = 1; j <= n; j++) {
				if (chars_strA[i - 1] == chars_strB[j - 1]) {
					matrix[i][j] = matrix[i - 1][j - 1] + 1;
				} else {
					matrix[i][j] = Math.max(matrix[i][j - 1], matrix[i - 1][j]);
				}
			}
		}
		// 矩阵中，如果matrix[m][n]的值不等于matrix[m-1][n]的值也不等于matrix[m][n-1]的值，
		// 则matrix[m][n]对应的字符为相似字符元，并将其存入result数组中。
		char[] result = new char[matrix[m][n]];
		int currentIndex = result.length - 1;
		while (matrix[m][n] != 0) {
			if (matrix[m][n] == matrix[m][n - 1]) {
				n--;
			} else if (matrix[m][n] == matrix[m - 1][n]) {
				m--;
			} else {
				result[currentIndex] = chars_strA[m - 1];
				currentIndex--;
				n--;
				m--;
			}
		}
		return new String(result);
	}

}
